
//filename:ipscopetbl.c
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include "ipscopetbl.h"

void init_ipscope_table(ipscope_table* list)
{
	list->m_num = 0;
	list->m_head = NULL;
	init_id_mgr(&(list->m_id_mgr));  

	return;
}

void clear_ipscope_table(ipscope_table* list)
{
	assert(NULL != list);

	struct ipscope *p = list->m_head;
	while(NULL != p){
		list->m_head = p->m_next;
		free(p);
		p = list->m_head;
	}//while

	list->m_num = 0;

	clear_id_mgr(&(list->m_id_mgr));
	return;
}

//start end ÎªÖ÷»úÐò
int add_ipscope2(ipscope_table* list, u_int32_t start, u_int32_t end,int flag)
{
	assert(NULL != list);

	struct ipscope *newitem = NULL;
	struct ipscope *pitem = NULL;

	if(start > end)
		return -ENOMEM;

	newitem  = (struct ipscope*)malloc(sizeof(struct ipscope));
	if (NULL == newitem)
		return -ENOMEM;

	newitem->m_next = NULL;
	newitem->m_id = getid_id_mgr(&(list->m_id_mgr));
	newitem->m_start = start;
	newitem->m_end = end;
	newitem->m_flag=flag;
	if (NULL == list->m_head){
		list->m_head = newitem;
	}
	else{
		pitem = list->m_head;
		if (newitem->m_start< pitem->m_start){
			newitem->m_next = pitem;
			list->m_head = newitem;
		}
		else{
			while(NULL != pitem->m_next){
				if (newitem->m_start< pitem->m_next->m_start){
					newitem->m_next = pitem->m_next;
					pitem->m_next = newitem;
					break;
				}
				pitem = pitem->m_next;
			}//while

			if (NULL == pitem->m_next)
				pitem->m_next = newitem;
		}
	}//else

	(list->m_num)++;

	return newitem->m_id;
}


//start end ÎªÖ÷»úIP
int add_ipscope(ipscope_table* list, u_int32_t start, u_int32_t end,int flag)
{

	/*
	-----(--------)--------[-------]------ 1
		
	-----[-------]--------(--------)------ 2

	-----(--------[--------)-------]------ 3

	-----[--------(--------]-------)------ 4

	-----[--------(--------)-------]------ 5

	-----(--------[--------]-------)------ 6
	*/

	assert(NULL != list);

	struct ipscope *tmpips, *tmpips0;
	int relation = 0;
	u_int32_t start0=start, end0=end;

	if(flag == 1)
	{

		tmpips=list->m_head;
		while(tmpips)
		{
			tmpips0 = tmpips->m_next;
			relation = 0;
			if(end0+1 < tmpips->m_start)
			{
				relation = 1;
				tmpips = tmpips0;
				continue;
			}
			if(start0 > tmpips->m_end+1)
			{
				relation = 2;
				tmpips = tmpips0;
				continue;
			}
			if(start0 < tmpips->m_start)
			{
				if(end0 <= tmpips->m_end)
				{
					end0 = tmpips->m_end;
					relation = 3;
				}
				else
				{
					relation = 6;
				}
			}
			else
			{
				if(end0 > tmpips->m_end)
				{
					relation = 4;
				}
				else
				{
					end0 = tmpips->m_end;
					relation = 5;
				}
				start0 = tmpips->m_start;
			}
			if(relation == 5)
				return 0;
			if(relation==3 || relation==4 || relation==6)
			{
				delete_ipscope(list, tmpips->m_id);
			}
			tmpips = tmpips0;	
		}
		add_ipscope2(list, start0, end0, flag);
	}
	else
	{
		tmpips=list->m_head;
		while(tmpips)
		{
			tmpips0 = tmpips->m_next;
			relation = 0;
			if(end0 < tmpips->m_start)
			{
				relation = 1;
				tmpips = tmpips0;
				continue;
			}
			if(start0 > tmpips->m_end)
			{
				relation = 2;
				tmpips = tmpips0;
				continue;
			}
			if(start0 <= tmpips->m_start)
			{
				if(end0 < tmpips->m_end)
				{
					relation = 3;
					tmpips->m_start = end0+1;
					if(tmpips->m_start > tmpips->m_end)
					{
						delete_ipscope(list, tmpips->m_id);
					}
				}
				else
				{
					relation = 6;
					delete_ipscope(list, tmpips->m_id);
				}
			}
			else
			{
				if(end0 >= tmpips->m_end)
				{
					relation = 4;
					tmpips->m_end = start0-1;
					if(tmpips->m_start > tmpips->m_end)
					{
						delete_ipscope(list, tmpips->m_id);
					}
				}
				else
				{
					relation = 5;
					u_int32_t start1, end1, start2, end2;
					
					start1 = tmpips->m_start;
					end1 = start0-1;

					start2 = end0+1;
					end2 = tmpips->m_end;

					delete_ipscope(list, tmpips->m_id);
					add_ipscope2(list, start1, end1, 1);
					add_ipscope2(list, start2, end2, 1);
				}
			}
			tmpips = tmpips0;
		}
	}

	return 0;
}

int delete_ipscope(ipscope_table* list, int id)
{
	assert(NULL != list);

	struct ipscope *p = NULL;
	struct ipscope *curitem = NULL;

	if (NULL == list->m_head)
		return -ENODATA;

	p = list->m_head;

	if (p->m_id == id){
		list->m_head = p->m_next;
		free(p);
		(list->m_num)--;
		releaseid_id_mgr(&(list->m_id_mgr), id);
		return 0;
	}

	while(NULL != p->m_next){
		if (p->m_next->m_id == id){
			curitem = p->m_next;
			p->m_next = curitem->m_next;
			free(curitem);
			(list->m_num)--;
			releaseid_id_mgr(&(list->m_id_mgr), id);
			return 0;
		}//if
		p = p->m_next;
	}//while

	return -ENODATA;

}

int get_ipscope(ipscope_table* list, int id, u_int32_t* start, u_int32_t* end)
{
	assert(NULL != start);
	assert(NULL != end);

	struct ipscope* pitem = list->m_head;
	while(NULL != pitem){
		if(id == pitem->m_id){
			*start = pitem->m_start;
			*end = pitem->m_end;
			break;
		}//if
		pitem = pitem->m_next;
	}//while

	if(NULL == pitem)
		return -ENODATA;
	else
		return 0;
}

void print_ipscope_table(const ipscope_table* list)
{
	assert(NULL != list);

	printf("the ipscope table contains %d items.\n", list->m_num);

	struct ipscope *p = list->m_head;
	while(NULL != p){
		printf("No.%d: %08x---%08x\n", p->m_id, p->m_start, p->m_end); 
		p = p->m_next;
	}//while

	return;
}

int export_ipscope_table(const ipscope_table* list, struct ipscope* tbl, int nmax)
{
	assert(NULL != list);
	assert(NULL != tbl);

	int i = 0;

	struct ipscope* pitem = list->m_head;
	while(NULL != pitem){
		if(i >= nmax)
			break;
		tbl[i].m_id = pitem->m_id;
		tbl[i].m_flag = pitem->m_flag;
		tbl[i].m_start = pitem->m_start;
		tbl[i].m_end = pitem->m_end;
		i++;
		pitem = pitem->m_next;
	}

	return i;

}

int unite_add_ipscope_table(const ipscope_table* table1, ipscope_table* table2, int max, int flag)
{
	assert(NULL != table1);
	assert(NULL != table2);

	int n = 0;
	
	struct ipscope* pitem = table1->m_head;
	while(NULL != pitem)
	{
		if(flag == 1)
		{
			if(pitem->m_flag == 1)
				add_ipscope(table2, pitem->m_start, pitem->m_end, pitem->m_flag);
		}
		else if(flag == 0)
		{
			if(pitem->m_flag == 0)
				add_ipscope(table2, pitem->m_start, pitem->m_end, pitem->m_flag);
		}
		else
		{
			add_ipscope(table2, pitem->m_start, pitem->m_end, pitem->m_flag);
		}
		pitem = pitem->m_next;
		if(table2->m_num >= max)
			return -1;
	}

	return table2->m_num;
}
